package io.github.luons.mediator.dsl.utils;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;

/**
 * mediatorUtils
 *
 * @author : luons
 */
@Slf4j
public class MediatorUtils {

    public static final Integer MAX_PAGE_SIZE = 1000;

    public static ThreadLocal<Page<Object>> PAGE_THREAD_LOCAL = ThreadLocal.withInitial(Page::new);

    private static final ConversionService conversionService = new DefaultConversionService();

    public static HttpServletRequest getHttpServletRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes instanceof ServletRequestAttributes) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
            return attributes.getRequest();
        }
        return null;
    }

    public static Object getRequestValueByKey(String key) {
        Object valueObj = null;
        HttpServletRequest servletRequest = getHttpServletRequest();
        if (Objects.isNull(servletRequest)) {
            return null;
        }
        Map<String, String[]> param = servletRequest.getParameterMap();
        if (param.containsKey(key) && param.get(key).length > 0) {
            valueObj = param.get(key)[0];
        } else if (servletRequest.getAttribute(key) != null) {
            valueObj = servletRequest.getAttribute(key);
        }
        return valueObj;
    }

    public static void setPageable(Integer pageNumber, Integer pageSize) {
        if (Objects.isNull(pageNumber) && Objects.isNull(pageSize)) {
            return;
        }
        if (Objects.nonNull(pageNumber) && pageNumber == -1) {
            return;
        }
        pageNumber = Objects.isNull(pageNumber) ? 1 : pageNumber;
        pageSize = Objects.isNull(pageSize) ? 10 : pageSize;
        pageSize = Math.min(pageSize, MAX_PAGE_SIZE);
        PAGE_THREAD_LOCAL.set(PageHelper.startPage(pageNumber, pageSize));
    }

    public static boolean containField(Class<?> clazz, String fieldName) {
        if (StringUtils.isBlank(fieldName)) {
            return false;
        }
        boolean exist = false;
        for (Field field : clazz.getDeclaredFields()) {
            if (Objects.nonNull(field)) {
                String name = field.getName();
                if (StringUtils.isNotBlank(name) && name.equals(fieldName)) {
                    exist = true;
                    break;
                }
            }
        }
        return exist;
    }

    public static Class<?> containFieldType(Class<?> clazz, String fieldName) {
        if (StringUtils.isBlank(fieldName)) {
            return null;
        }
        return Arrays.stream(clazz.getDeclaredFields()).filter(field -> StringUtils.isNotBlank(field.getName())
                        && fieldName.equals(field.getName()))
                .findFirst().map(Field::getType).orElse(null);
    }

    public static void setupDataObject(Object dataObj, String fieldName, Object fieldValue) throws Exception {
        if (Objects.isNull(dataObj)) {
            return;
        }
        Field[] fields = dataObj.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (!fieldName.equals(field.getName())) {
                continue;
            }
            field.setAccessible(true);
            if (Objects.nonNull(field.get(dataObj))) {
                continue;
            }
            if (fieldValue instanceof Enum && field.getType().getName().equals(String.class.getName())) {
                field.set(dataObj, ((Enum<?>) fieldValue).name());
                continue;
            }
            if (!(fieldValue.getClass().toString()).equalsIgnoreCase(field.getType().toString())) {
                continue;
            }
            field.set(dataObj, fieldValue);
            break;
        }
    }

    public static <T> T convert(Object value, Class<T> targetType) {
        if (targetType.isInstance(value)) {
            return targetType.cast(value);
        }
        return conversionService.convert(value, targetType);
    }

    public static String convertEnhanced(String camelCaseStr) {
        if (camelCaseStr == null) return null;

        StringBuilder result = new StringBuilder();
        char[] chars = camelCaseStr.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            char c = chars[i];
            if (Character.isUpperCase(c)) {
                if (i > 0 && (Character.isLowerCase(chars[i - 1]) || (i < chars.length - 1 && Character.isLowerCase(chars[i + 1])))) {
                    result.append('_');
                }
                result.append(Character.toLowerCase(c));
            } else {
                result.append(c);
            }
        }
        return result.toString();
    }

}
